/*
 * Team members: Fabio Canache    ID: 564693
 *               Denise Videtta   ID: 565525
 * Date:         10/06/2008
 * 
 * Project #1 - Question: 2a GoL Version 1
 * 
 * ALG 2008 Fall
 * Instructor: Dr. Oleg Komogortsev, TSU
 * 
 */

package gameoflife;

/**
 *  This class implement the Game of Life Version 1  
 * 
 */
public class GameOfLife extends Thread  {
    
    private lifequeen.LifeQueen lifeQueen;
    
    private int maxRow;
    private int maxColumn;
    private final boolean ALIVE = true;
    private final boolean DEAD = false;
    
    public int conf[][];
    
    public boolean map[][];
    public boolean nextMap[][];
    
    private int numberDeads;
    private int numberBorns;
    private int generationCounter;
    
    
    public GameOfLife (lifequeen.LifeQueen lifeQueen) {
        this.lifeQueen = lifeQueen;
    }
    
    @Override
    public void run () {
        this.startGameOfLife();
    }
    
    
    /**
     *  Starts the Game of Life Version 1 process until the user does not want
     *  more generations
     */
    private void startGameOfLife() {
        
        generationCounter = 0;
        
        maxRow = this.lifeQueen.getGoLNBoardSize();
        maxColumn = this.lifeQueen.getGoLMBoardSize();
        map = new boolean[maxRow + 2][maxColumn + 2];
        nextMap = new boolean[maxRow + 2][maxColumn + 2];
        
        initialization();
        
        try {
            
            do {
                
                generationCounter++;
                
                for (int i = 1; i <= maxRow; i++) {
                    for (int j = 1; j <= maxColumn; j++) {

                        switch (countNeighbors(i, j)) {
                            case 0:
                            case 1:
                                nextMap[i][j] = DEAD;
                                if (map[i][j] != DEAD) {
                                    this.numberDeads++;
                                }
                                break;
                            case 2:
                                nextMap[i][j] = map[i][j];
                                break;
                            case 3:
                                nextMap[i][j] = ALIVE;
                                if (map[i][j] != ALIVE) {
                                    this.numberBorns++;
                                }
                                break;
                            case 4:
                            case 5:
                            case 6:
                            case 7:
                            case 8:
                                nextMap[i][j] = DEAD;
                                if (map[i][j] != DEAD) {
                                    this.numberDeads++;
                                }
                                break;

                        }
                    }
                }
                
                updateMap();             
                
                printMap();
                
                lifeQueen.setGoLNewBorns(Integer.toString(this.numberBorns));
                lifeQueen.setGoLNewDeads(Integer.toString(this.numberDeads));
                lifeQueen.setGoLDescriptionArea("This is the generation number: " + this.generationCounter + "\nTotal number of changes: " + (this.numberBorns + this.numberDeads));
                
                this.numberDeads = 0;
                this.numberBorns = 0;
                
                lifeQueen.setContinueToNextGeneration(true);
                while (lifeQueen.getContinueToNextGeneration()) {
                
                }
                
            } while (lifeQueen.getExecuteGoL());

        } catch (Exception e) {
            
        }
    }

    /**
     *  Initialize the first configuration for the board with the
     *  user entries for "Alive" cells
     */
    public void initialization() {
        
        conf = lifeQueen.getGoLBoardConfiguration();
        
        for (int i = 0; i <= maxRow+1; i++) {
            for (int j = 0; j <= maxColumn+1; j++) {
                /* If is in the file*/
                if (conf[i][j] == 1) {
                    map[i][j] = ALIVE;
                } else {
                    map[i][j] = DEAD;
                }
            }
        }
    }

    /**
     *  Print the current generation in the board
     */
    public void printMap() {

        for (int i = 1; i <= maxRow; i++) {

            for (int j = 1; j <= maxColumn; j++) {

                if (map[i][j] == ALIVE) {
                    lifeQueen.placeAlive((i - 1), (j - 1));
                } else {
                    lifeQueen.removeAlive((i - 1), (j - 1));
                }
            }
 
        }
    }

    /**
     *  Update the map with the next generation in the board to be displayed
     */
    public void updateMap() {

        for (int i = 0; i <= maxRow + 1; i++) {

            for (int j = 0; j <= maxColumn + 1; j++) {
                map[i][j] = nextMap[i][j];
            }

        }
    }

    /**
     *  Return the number of neighbors for a specific cell
     */
    public int countNeighbors(int row, int col) {

        int numberNeighbors = 0;

        for (int i = row - 1; i <= row + 1; i++) {

            for (int j = col - 1; j <= col + 1; j++) {

                if (map[i][j] == ALIVE) {
                    numberNeighbors++;
                }
            }

        }
        if (map[row][col] == ALIVE) {
            numberNeighbors--;
        }

        return numberNeighbors;

    }

}
